package article

import (
	"context"
	"fmt"
	"gitee.com/DonHz/basic-go/webook/internal/domain"
	"gorm.io/gorm"
	"gorm.io/gorm/clause"
	"time"
)

type ArticleDAO interface {
	Insert(ctx context.Context, article Article) (int64, error)
	UpdateByArticleId(ctx context.Context, article Article) error
	Sync(ctx context.Context, article Article) (int64, error)
	Upsert(ctx context.Context, article ReaderArticle) error
	SyncStatus(ctx context.Context, article Article) error
	GetByAuthor(ctx context.Context, art domain.Article, offset int, limit int) ([]Article, error)
	GetById(ctx context.Context, uid int64) (Article, error)
	GetPubById(ctx context.Context, id int64) (ReaderArticle, error)
}

type GormArticleDAO struct {
	db *gorm.DB
}


func NewArticleDAO(db *gorm.DB) ArticleDAO {
	return &GormArticleDAO{
		db: db,
	}
}

func (dao *GormArticleDAO) Insert(ctx context.Context, article Article) (int64, error) {
	now := time.Now().UnixMilli()
	article.CreateTime = now
	article.UpdateTime = now
	err := dao.db.WithContext(ctx).Create(&article).Error
	return article.Id, err
}

func (dao *GormArticleDAO) UpdateByArticleId(ctx context.Context, article Article) error {
	now := time.Now().UnixMilli()
	article.UpdateTime = now
	res := dao.db.WithContext(ctx).Model(&article).
		Where("id=? AND author_id=?", article.Id, article.AuthorId).
		Updates(map[string]any{
			"title":       article.Title,
			"content":     article.Content,
			"status":      article.Status,
			"update_time": article.UpdateTime,
		})
	if res.Error != nil {
		return res.Error
	}
	if res.RowsAffected == 0 {
		return fmt.Errorf("更新失败，创作者非法, id: %d, authorId: %d",
			article.Id, article.AuthorId)
	}
	return res.Error
}

func (dao *GormArticleDAO) Sync(ctx context.Context, article Article) (int64, error) {
	var (
		id = article.Id
	)
	// 开启事务
	err := dao.db.Transaction(func(tx *gorm.DB) error {
		var err error
		txDAO := NewArticleDAO(tx)
		if id == 0 {
			id, err = txDAO.Insert(ctx, article)
		} else {
			err = txDAO.UpdateByArticleId(ctx, article)
		}
		if err != nil {
			return err
		}
		// 操作线上库
		return txDAO.Upsert(ctx, ReaderArticle{Article: article})
	})
	return id, err
}

func (dao *GormArticleDAO) Upsert(ctx context.Context, article ReaderArticle) error {
	now := time.Now().UnixMilli()
	article.CreateTime = now
	article.UpdateTime = now
	// OnConflict 数据冲突了
	// INSERT xxx ON DUPLICATE KEY UPDATE xxx
	err := dao.db.Clauses(clause.OnConflict{
		// MySQL 只需要关心这里
		DoUpdates: clause.Assignments(map[string]interface{}{
			"title":       article.Title,
			"content":     article.Content,
			"update_time": now,
			"status":      article.Status,
		}),
	}).Create(&article).Error
	return err
}

func (dao *GormArticleDAO) SyncStatus(ctx context.Context, article Article) error {
	now:=time.Now().UnixMilli()
	err := dao.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
		res:=tx.Model(&Article{}).
			Where("id=? AND author_id = ?", article.Id,article.AuthorId).
			Updates(map[string]interface{}{
				"status":article.Status,
				"update_time": now,
		})
		if res.Error!=nil{
			return res.Error
		}
		if res.RowsAffected == 0 {
			// id 或者 作者id 不对
			return fmt.Errorf("更新失败，创作者非法, id: %d, authorId: %d",
				article.Id, article.AuthorId)
		}
		
		res = tx.Model(&ReaderArticle{}).
			Where("id=? AND author_id = ?", article.Id,article.AuthorId).
			Updates(map[string]interface{}{
			"status":article.Status,
			"update_time": now,
		})
		if res.Error!=nil{
			return res.Error
		}
		if res.RowsAffected == 0 {
			// id 或者 作者id 不对
			return fmt.Errorf("更新失败，创作者非法, id: %d, authorId: %d",
				article.Id, article.AuthorId)
		}
		return nil
	})
	return err
}

func (dao *GormArticleDAO) GetByAuthor(ctx context.Context, art domain.Article, offset int, limit int) ([]Article, error){
	var arts []Article
	err:=dao.db.WithContext(ctx).Model(&Article{}).
		Where("author_id= ?", art.Author.Id).
		Offset(offset).
		Limit(limit).
		//Order("update_time DESC").
		Order(clause.OrderBy{Columns: []clause.OrderByColumn{
			{Column: clause.Column{Name: "update_time"}, Desc: true},
			{Column: clause.Column{Name: "create_time"}, Desc: false},
		}}).Find(&arts).Error
	return arts, err
}

func (dao *GormArticleDAO) GetById(ctx context.Context, uid int64) (Article, error) {
	var art Article
	err:=dao.db.WithContext(ctx).Model(&Article{}).Where("author_id= ?", uid).Find(&art).Error
	return art, err
}

// 这是制作库
type Article struct {
	Id      int64  `gorm:"primaryKey, autoIncrement"`
	Title   string `gorm:"varchar(1024)"`
	Content string `gorm:"BLOB"`
	// 设计索引
	// 查看所有创作者的所有文章
	// SELECT * FROM articles WHERE author_id = 123 ORDER BY `create_time` DESC;
	// 创建联合索引
	AuthorId   int64 `gorm:"index"`
	Status     uint8
	CreateTime int64
	//// 创建联合索引
	//AuthorId int64	`gorm:"index=aid_ctime"`
	//CreateTime int64 `gorm:"index=aid_ctime"`
	// 更新时间，单位：毫秒 ms
	UpdateTime int64
}


func (dao *GormArticleDAO) GetPubById(ctx context.Context, id int64) (ReaderArticle, error) {
	return ReaderArticle{}, nil
}